#include "../head/func.h"
#include <iostream>
using namespace std;

void createFile()
{
  string filename;
  if (!getParam(filename))
  {
    cout << "You need to input the file size...\n";
    return;
  }
  string size;
  getParam(size);
  if (filename == "")
  {
    cout << "The command lack of filename\n";
    return;
  }
  int filesize;
  try
  {
    filesize = stoi(size);
  }
  catch (const std::exception &e)
  {
    cout << "filesize need to be a integer" << '\n';
    return;
  }
  if (!parse(filename, stand, temp))
  {
    cout << "The path is not right\n";
    return;
  }
  if (findName(temp, filename))
  {
    cout << filename << " has exit...\n";
    return;
  }
  int new_inode = buildInode(Mode::RW, Type::REG, filesize,filename);
  Entry *entry = new Entry;
  entry->inode_index = new_inode;
  strcpy(entry->file_name, filename.c_str());
  addEntry(temp, entry);
  delete entry;
  if (temp->id == stand->id)
  {
    stand->f_size = temp->f_size;
    for (int i = 0; temp->i_zone[i] != -1; i++)
      stand->i_zone[i] = temp->i_zone[i];
  }
}

void listDir()
{
  cout << setiosflags(ios::left) << setw(12) << "File Name" << setw(8) << "Type"
       << setw(8) << "Mode" << setw(8) << "Size" << setw(8) << "Create Time" << endl;
  listInfo(stand);
}

void createDir()
{
  string dirname;
  getParam(dirname);
  if (dirname == "")
  {
    cout << "The dir name can't be empty\n";
    return;
  }
  if (!parse(dirname, stand, temp))
  {
    cout << "The path is not right\n";
    return;
  }
  if (findName(temp, dirname))
  {
    cout << dirname << " has exit...\n";
    return;
  }
  int new_inode = buildInode(Mode::RW, Type::DIR, 1,dirname);

  Entry *entry = new Entry;
  entry->inode_index = new_inode;
  strcpy(entry->file_name, dirname.c_str());
  addEntry(temp, entry);
  delete entry;
  if (temp->id == stand->id)
  {
    stand->f_size = temp->f_size;
    for (int i = 0; temp->i_zone[i] != -1; i++)
      stand->i_zone[i] = temp->i_zone[i];
  }

  Entry *f_entry = new Entry;
  f_entry->inode_index = temp->id;
  strcpy(f_entry->file_name, "..");
  fseek(fp, superblock->inode_base + sizeof(Inode) * new_inode, SEEK_SET);
  fread(temp, sizeof(Inode), 1, fp);
  addEntry(temp, f_entry);
  delete f_entry;
  //memcpy(stand, temp, sizeof(Inode));
}

void changeDir(string &pwd)
{
  string dirname;
  getParam(dirname);
  if (dirname == "")
  {
    cout << "The dir name can't be empty\n";
    return;
  }
  string path = dirname;
  if (!parse(dirname, stand, temp))
  {
    if (dirname == "/")
    {
      memcpy(stand, root, sizeof(Inode));
      pwd = "/";
      return;
    }
    cout << "The path is not right\n";
    return;
  }
  if (findInode(temp, dirname) && temp->f_type == Type::DIR)
  {
    memcpy(stand, temp, sizeof(Inode));
    if (path[0] == '/')
      pwd = path;
    else if (path.substr(0, 2) == "..")
    {
      int index = pwd.find_last_of('/');
      pwd = pwd.substr(0, index) + path.substr(2, path.length() - 2);
      if (pwd == "")
        pwd = "/";
    }
    else
    {
      if (pwd != "/")
        pwd += '/';
      pwd += path;
    }
  }
}

void deleteFile()
{
  string filename;
  getParam(filename);
  if (filename == "" || filename == "..")
  {
    cout << "The command lack of filename\n";
    return;
  }
  if (!parse(filename, stand, temp))
  {
    cout << "The path is not right\n";
    return;
  }
  Inode *inode = new Inode();
  memcpy(inode, temp, sizeof(Inode));
  if (!findInode(temp, filename))
  { //现在的temp是filname的i_node
    cout << filename << "has not exit...\n";
    return;
  }
  deleteInode(temp);
  deleteEntry(inode, filename);
  if (inode->id == stand->id)
  {
    stand->f_size = inode->f_size;
    for (int i = 0; inode->i_zone[i] != -1; i++)
      stand->i_zone[i] = inode->i_zone[i];
  }
  
  delete inode;
}

void cp()
{
  //把f1赋值给f2
  string f1;
  string f2;
  if (!getParam(f1))
  {
    cout << "You need to input the destination file...\n";
    return;
  }
  getParam(f2);
  if (!parse(f1, stand, temp))
  {
    cout << "The path is not right\n";
    return;
  }
  if (f1 == ".." || f1 == "")
  {
    cout << "The format of filename is wrong...\n";
    return;
  }
  Inode *source0 = new Inode();
  memcpy(source0, temp, sizeof(Inode));
  if (!findInode(temp, f1))
  {
    cout << f1 << " not exit...\n";
    return;
  }
  Inode *source = new Inode();
  memcpy(source, temp, sizeof(Inode));

  if (!parse(f2, stand, temp))
  {
    cout << "The path is not right\n";
    return;
  }
  if (f2 == ".." || f2 == "")
  {
    cout << "The format of filename is wrong...\n";
    return;
  }
  Inode *dest = new Inode();
  if (!findInode(temp, f2))
  {
    int new_inode = buildInode(Mode::RW, Type::REG, source->f_size,f2);
    fseek(fp, superblock->inode_base + sizeof(Inode) * new_inode, SEEK_SET);
    fread(dest, sizeof(Inode), 1, fp);
    Entry *entry = new Entry;
    entry->inode_index = new_inode;
    strcpy(entry->file_name, f2.c_str());
    addEntry(temp, entry);
    delete entry;
  }
  else
  {
    memcpy(dest, temp, sizeof(Inode));
  }
  if (source->f_type == Type::DIR || dest->f_type == Type::DIR)
  {
    cout << "we can not copy dir.../n";
  }
  //处理两个文件大小不一
  if (source->f_size > dest->f_size)
  {
    if (source->f_size <=10)
    {
      for (int i = dest->f_size; i < source->f_size; i++)
      {
        dest->i_zone[i] = getAvaiData();
      }
    }
    else
    {
      int acount[1024 / 4];
      if (dest->f_size <= 10)
      {
        for (int i = dest->f_size; i < 10; i++)
        {
          dest->i_zone[i] = getAvaiData();
        }
        dest->i_zone[10] = getAvaiData();
        for (int i = 0; i < source->f_size - 10 ; i++)
        {
          acount[i] = getAvaiData();
        }
        fseek(fp, superblock->data_base + 1024 * dest->i_zone[10], SEEK_SET); 
        fwrite(acount, (source->f_size - 10) * 4, 1, fp);  
      }else{
        for (int i = dest->f_size-10-1; i < source->f_size-10 ; i++)
        {
          acount[i] = getAvaiData();
        }
        fseek(fp, superblock->data_base + 1024 * dest->i_zone[10], SEEK_SET); 
        fwrite(acount, (source->f_size - 10) * 4, 1, fp);  
      }
    }
    dest->f_size = source->f_size;
  }
  if (source->f_size < dest->f_size)
  {
    if(dest->f_size<=10){
      for (int i = source->f_size; i < dest->f_size; i++){
        releaseData(dest->i_zone[i]);
        dest->i_zone[i] = -1;
      }
    }else{
      int acount[1024/4];
      fseek(fp, superblock->data_base + 1024 * dest->i_zone[10], SEEK_SET); 
      fread(acount, (dest->f_size - 10) * 4, 1, fp);  
      if(source->f_size>=10){
        for(int i = source->f_size-10;i<dest->f_size-10;i++){
          releaseData(acount[i]);
        }
      }else{
        for(int i = source->f_size;i<=10;i++){
          releaseData(dest->i_zone[i]);
          dest->i_zone[i] = -1;
        }
      }
    }
    dest->f_size = source->f_size;
  }
  int acount1[1024 / 4];
  int acount2[1024 / 4];
  if (source->f_size > 10)
  {
    fseek(fp,
          superblock->data_base + 1024 * source->i_zone[10],
          SEEK_SET);
    fread(acount1, (source->f_size - 10)*4, 1, fp);
    fseek(fp,
          superblock->data_base + 1024 * dest->i_zone[10],
          SEEK_SET);
    fread(acount2, (dest->f_size - 10)*4, 1, fp);
  }
  for (int i = 0; i < source->f_size; i++)
  {
    if (i < 10)
    {
      cpdata(source->i_zone[i],dest->i_zone[i]);
    }
    else
    {
      cpdata(acount1[i - 10],acount2[i - 10]);
    }
 
  }
  fseek(fp, superblock->inode_base + sizeof(Inode) * dest->id, SEEK_SET);
  fwrite(dest, sizeof(Inode), 1, fp);
}

void cat()
{
  string filename;
  getParam(filename);
  if (filename == "")
  {
    cout << "The command lack of filename\n";
    return;
  }
  if (!parse(filename, stand, temp))
  {
    cout << "The path is not right\n";
    return;
  }
  if (!findInode(temp, filename))
  {
    cout << filename << " has not exit...\n";
    return;
  }
  int block_id = 0;
  int acount[1024/4];
  if(temp->f_size>10){
    fseek(fp,
          superblock->data_base + 1024 * temp->i_zone[10],
          SEEK_SET);
    fread(acount, (temp->f_size - 10)*4, 1, fp);
  }
  for (int i = 0; i < temp->f_size; i++)
  {
    if(i<10){
      block_id = temp->i_zone[i];
    }else{
      block_id = acount[i-11];
    }
    char str[1025];
      fseek(fp, superblock->data_base + 1024 * block_id, SEEK_SET);
      fread(str, 1024, 1, fp);
      str[1024] = '\0';
      cout << str;
  }
  cout<<endl;
}

void sum()
{
  int super = 1;
  int num_inode = 0;
  int num_data = 0;
  for (int i = 0; i < 1024; i++)
  {
    if (inode_bit_map[i] == 1)
    {
      num_inode += 1;
    }
    if (data_bit_map[i] == 1)
    {
      num_data += 1;
    }
  }
  num_inode = num_inode * sizeof(Inode) / 1024 + 1;
  int used = super + num_inode + num_data;
  cout << "super: " << super << endl;
  cout << "inode " << num_inode << endl;
  cout << "data " << num_data << endl;
  cout << "used block: " << used << endl;
  cout << "unused block: " << 16 * 1024 - used << endl;
}